ZIP.namespace('Cache.Widget');
////////////////////////////////////////////////////////////////////////////////////////
// Example use:
// var con = ZIP.Widget.Console.init().display().log(ob);
//
ZIP.Cache.Widget.Console = function(Z) {
    // nothing clever about this widget.  all it does is take an item and append it to it's
    // instance

    // global defaults
    var _defaultLogOptions = {
            timestampEnabled: false,
            debugEnabled: true,
            warningEnabled: true,
            errorEnabled: true,
            infoEnabled: true,
            tableDepth: 3
        },
        _globalOptions = ZIP.System.deepCopy(_defaultLogOptions);
    
    function _constructor(logOptions) {
       
        // heading is the heading, which describes the payLoad and can be null
        // payLoad can be a simple type or an object
        var _logOptions = ZIP.System.replace(_globalOptions, logOptions),   // set the logging options
            _appWindow, _loggerDOM;
            
        // reset options so other instances get the default options initially
        _globalOptions = ZIP.System.deepCopy(_defaultLogOptions);
            
        // create the logger's container
        _loggerDOM = document.createElement('div');
        _loggerDOM.id = ZIP.System.uid();
        _loggerDOM.classname = 'ZIPlogConsole';
        
        _loggerDOM.style.width = '100%';
        _loggerDOM.style.wordWrap = 'break-word';

        //  get the app window for this logger and connect the loggerDOM to it
        _appWindow = Z.Widget.AppWindow.init().view(_loggerDOM);

        function _enableOption(cat) {
            // cat = debug|warn|error|info
            logOptions[cat+'Enabled'] = true;
            return this;
        }
        function _disableOption(cat) {
            // cat = debug|warn|error|info
            logOptions[cat+'Enabled'] = false;
            return this;
        }
        function _getOptions(dst) {
            // copy the options for this instance into the provided parameter
            if (dst) dst = ZIP.System.shallowCopy(_logOptions);
            return this;
        }
        function _setTableDepth(depth) {
            _logOptions.tableDepth = depth;
            return this;
        }
        
        function _display(withHeader) {
            _appWindow.setTitle(withHeader || 'Console Window').display(true);
            return this;
        }
        
        // clear the console window; remove all the child elements within _loggerDOM
        function _clear() {          
            while ( _loggerDOM.children.length > 0 ) {
                _loggerDOM.removeChild(_loggerDOM.children[0]);
            }
            return this;
        }
        
        function _close() {
            // close down the console widget.  ensure all dom elements are removed from the DOM
            // and then delete the instance.
            _clear();
            
            // remove the _loggerDOM node from the appWindow
            _appWindow.close();
            
            return this;
        }
        
        // the normal logging method.. we will just append the payLoad to the AppWindow
        function _log(payLoad) {
            var _entry;
            
            if (typeof payLoad == 'object') {
                // create the DOM table for the object
                _entry = _getDOMTable(payLoad, 0, _logOptions.tableDepth );
                
            }
            else {
                payLoad = [new Date(), (payLoad?payLoad:'')].join(' ');
                // create the payLoad DOM element.. in this case a text node will do
                _entry = document.createElement('div');
                _entry.style.borderBottom = '1px solid black';
                _entry.style.background = 'yellow';
                _entry.appendChild(document.createTextNode(payLoad));
            }
            
            _loggerDOM.appendChild(_entry);
            return this;
        }
        
        return {
            enableOption: _enableOption,
            disableOption: _disableOption,
            getOptions: _getOptions,
            display: _display,
            clear: _clear,
            close: _close,
            logWindow: _appWindow,
            log: _log,          // the logging method
            setTableDepth: _setTableDepth,
        };
        
    }  // _constructor
    
    
    function _getDOMTable(object, level, tableDepth) {
       // If we've reached maximum table depth, return a Text node instead.
       if (level > tableDepth)
          return document.createTextNode(object.toString());

       // Create the table we'll be returning
       var table = document.createElement("table");
       table.border = 1;
       table.width = '100%';
       
       // Add a Name|Type|Value header to the table
       var header = document.createElement("tr");
       if (level == 0) { 
          // start of the table.. set background to the logLevel colour..
          header.style.backgroundColor = 'red';  // just set it red for now
       }
       var headerName = document.createElement("th");
       var headerType = document.createElement("th");
       var headerValue = document.createElement("th");
       headerName.appendChild(document.createTextNode("Name"));
       headerType.appendChild(document.createTextNode("Type"));
       headerValue.appendChild(document.createTextNode("Value"));
       header.appendChild(headerName);
       header.appendChild(headerType);
       header.appendChild(headerValue);
       table.appendChild(header);

       // Get property names of the object and sort them alphabetically
       var names = [];
       for(var name in object) names.push(name);
       names.sort();

       // Now loop through those properties
       for(var i = 0; i < names.length; i++) {
          var name, value, type;
          name = names[i];
          try {
             value = object[name];
             type = typeof value;
          }
          catch(e) { // This should not happen, but it can in Firefox
             value = "<unknown value>";
             type = "unknown";
          };

          // Skip this property if it is rejected by a filter  **********later
          // if (log.options.filter && !log.options.filter(name, value)) continue;

          // Never display function source code: it takes up too much room
          if (type == "function") value = "{/*source code suppressed*/}";
          
          // Create a table row to display property name, type and value
          var row = document.createElement("tr");
          row.vAlign = "top";
          var rowName = document.createElement("td");
          var rowType = document.createElement("td");
          var rowValue = document.createElement("td");
                    
          rowName.appendChild(document.createTextNode(name));
          rowType.appendChild(document.createTextNode(type));

          // For objects, recurse to display them as tables
          if (type == "object")
             rowValue.appendChild(_getDOMTable(value, level+1, tableDepth));
          else
             rowValue.appendChild(document.createTextNode(value));

          // Add the cells to the row, and add the row to the table
          row.appendChild(rowName);
          row.appendChild(rowType);
          row.appendChild(rowValue);
          table.appendChild(row);
       }

       // Finally, return the table.
       return table;

    }  // _getDOMTable
    
        
    function Widget(options) { 
        // if this is called as Console(option).init() we set the global options.
        _globalOptions = ZIP.System.replace(_defaultLogOptions, options);
        return Widget;
    }
    Widget.init = _constructor;
    return Widget;
    
};  // ZIP.Cache.Widget.Console
